package com.core.cloudbusiness.system.device.service.impl;

import com.alibaba.fastjson.JSON;
import com.core.cloudbusiness.system.device.service.UserDeviceService;
import com.core.cloudcommon.redis.service.CloudRedisTemplateService;
import com.core.cloudcommon.redis.vo.CloudRedisVO;
import com.core.cloudcommon.security.ConcurrentLoginManager;
import com.core.cloudcommon.security.JwtTokenUtil;
import com.core.cloundbusinessapi.system.device.dto.UserDeviceDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.security.MessageDigest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author =====Lqj=====
 * @className UserDeviceServiceImpl
 * @description 用户设备管理服务实现
 * @create 2024/12/16 16:00
 **/
@Slf4j
@Service
public class UserDeviceServiceImpl implements UserDeviceService {

    @Autowired
    private CloudRedisTemplateService cloudRedisTemplateService;

    @Autowired
    private ConcurrentLoginManager concurrentLoginManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    // Redis Key前缀
    private static final String TRUSTED_DEVICES_KEY = "trusted_devices:";
    private static final String DEVICE_LOGIN_ATTEMPTS_KEY = "device_login_attempts:";

    @Override
    public List<UserDeviceDTO> getUserDevices(Long userId) {
        try {
            List<ConcurrentLoginManager.LoginDevice> devices = concurrentLoginManager.getUserDevices(userId);
            return devices.stream()
                    .map(this::convertToUserDeviceDTO)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("获取用户设备列表失败: {}", e.getMessage(), e);
            return new ArrayList<>();
        }
    }

    @Override
    public List<UserDeviceDTO> getOnlineDevices(Long userId) {
        List<UserDeviceDTO> allDevices = getUserDevices(userId);
        return allDevices.stream()
                .filter(device -> device.isActive(30)) // 30分钟内活跃的设备
                .peek(device -> device.setIsOnline(true))
                .collect(Collectors.toList());
    }

    @Override
    public UserDeviceDTO getDeviceByToken(String token) {
        try {
            Long userId = concurrentLoginManager.getUserIdFromToken(token);
            if (userId == null) {
                return null;
            }

            List<ConcurrentLoginManager.LoginDevice> devices = concurrentLoginManager.getUserDevices(userId);
            for (ConcurrentLoginManager.LoginDevice device : devices) {
                if (token.equals(device.getToken())) {
                    UserDeviceDTO deviceDTO = convertToUserDeviceDTO(device);
                    deviceDTO.setIsCurrent(true);
                    return deviceDTO;
                }
            }
        } catch (Exception e) {
            log.error("根据token获取设备信息失败: {}", e.getMessage(), e);
        }
        return null;
    }

    @Override
    public boolean kickOutDevice(Long userId, String deviceId) {
        try {
            List<ConcurrentLoginManager.LoginDevice> devices = concurrentLoginManager.getUserDevices(userId);
            for (ConcurrentLoginManager.LoginDevice device : devices) {
                if (deviceId.equals(device.getDeviceId())) {
                    concurrentLoginManager.handleUserLogout(userId, device.getToken());
                    log.info("踢出设备成功，用户: {}, 设备: {}", userId, deviceId);
                    return true;
                }
            }
        } catch (Exception e) {
            log.error("踢出设备失败: {}", e.getMessage(), e);
        }
        return false;
    }

    @Override
    public int kickOutOtherDevices(Long userId, String currentToken) {
        try {
            List<ConcurrentLoginManager.LoginDevice> devices = concurrentLoginManager.getUserDevices(userId);
            int kickedCount = 0;
            
            for (ConcurrentLoginManager.LoginDevice device : devices) {
                if (!currentToken.equals(device.getToken())) {
                    concurrentLoginManager.handleUserLogout(userId, device.getToken());
                    kickedCount++;
                }
            }
            
            log.info("踢出其他设备成功，用户: {}, 踢出数量: {}", userId, kickedCount);
            return kickedCount;
        } catch (Exception e) {
            log.error("踢出其他设备失败: {}", e.getMessage(), e);
            return 0;
        }
    }

    @Override
    public void updateDeviceActiveTime(String token) {
        concurrentLoginManager.updateDeviceActiveTime(token);
    }

    @Override
    public boolean renameDevice(Long userId, String deviceId, String newName) {
        try {
            List<ConcurrentLoginManager.LoginDevice> devices = concurrentLoginManager.getUserDevices(userId);
            for (ConcurrentLoginManager.LoginDevice device : devices) {
                if (deviceId.equals(device.getDeviceId())) {
                    device.setDeviceName(newName);
                    // 这里需要更新Redis中的设备信息
                    // 由于ConcurrentLoginManager的限制，这里简化处理
                    log.info("设备重命名成功，用户: {}, 设备: {}, 新名称: {}", userId, deviceId, newName);
                    return true;
                }
            }
        } catch (Exception e) {
            log.error("设备重命名失败: {}", e.getMessage(), e);
        }
        return false;
    }

    @Override
    public boolean isDeviceTrusted(Long userId, String deviceId) {
        try {
            String key = TRUSTED_DEVICES_KEY + userId;
            Object trustedDevices = cloudRedisTemplateService.get(new CloudRedisVO(key));
            
            if (trustedDevices != null) {
                Set<String> deviceSet = JSON.parseObject(trustedDevices.toString(), Set.class);
                return deviceSet.contains(deviceId);
            }
        } catch (Exception e) {
            log.error("检查设备可信状态失败: {}", e.getMessage(), e);
        }
        return false;
    }

    @Override
    public boolean trustDevice(Long userId, String deviceId) {
        try {
            String key = TRUSTED_DEVICES_KEY + userId;
            Object trustedDevices = cloudRedisTemplateService.get(new CloudRedisVO(key));
            
            Set<String> deviceSet;
            if (trustedDevices != null) {
                deviceSet = JSON.parseObject(trustedDevices.toString(), Set.class);
            } else {
                deviceSet = new HashSet<>();
            }
            
            deviceSet.add(deviceId);
            cloudRedisTemplateService.set(new CloudRedisVO(key, JSON.toJSONString(deviceSet), -1L));
            
            log.info("设备设置为可信成功，用户: {}, 设备: {}", userId, deviceId);
            return true;
        } catch (Exception e) {
            log.error("设置设备可信失败: {}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean untrustDevice(Long userId, String deviceId) {
        try {
            String key = TRUSTED_DEVICES_KEY + userId;
            Object trustedDevices = cloudRedisTemplateService.get(new CloudRedisVO(key));
            
            if (trustedDevices != null) {
                Set<String> deviceSet = JSON.parseObject(trustedDevices.toString(), Set.class);
                deviceSet.remove(deviceId);
                cloudRedisTemplateService.set(new CloudRedisVO(key, JSON.toJSONString(deviceSet), -1L));
                
                log.info("取消设备可信成功，用户: {}, 设备: {}", userId, deviceId);
                return true;
            }
        } catch (Exception e) {
            log.error("取消设备可信失败: {}", e.getMessage(), e);
        }
        return false;
    }

    @Override
    public List<Map<String, Object>> getDeviceLoginHistory(Long userId, String deviceId, int limit) {
        // 这里可以查询登录日志表获取设备的登录历史
        // 简化实现，返回空列表
        return new ArrayList<>();
    }

    @Override
    public int cleanOfflineDevices(Long userId, int offlineMinutes) {
        try {
            List<UserDeviceDTO> devices = getUserDevices(userId);
            int cleanedCount = 0;
            
            for (UserDeviceDTO device : devices) {
                if (!device.isActive(offlineMinutes)) {
                    kickOutDevice(userId, device.getDeviceId());
                    cleanedCount++;
                }
            }
            
            log.info("清理离线设备完成，用户: {}, 清理数量: {}", userId, cleanedCount);
            return cleanedCount;
        } catch (Exception e) {
            log.error("清理离线设备失败: {}", e.getMessage(), e);
            return 0;
        }
    }

    @Override
    public Map<String, Object> getDeviceStatistics(Long userId) {
        Map<String, Object> statistics = new HashMap<>();
        
        try {
            List<UserDeviceDTO> devices = getUserDevices(userId);
            List<UserDeviceDTO> onlineDevices = getOnlineDevices(userId);
            
            statistics.put("totalDevices", devices.size());
            statistics.put("onlineDevices", onlineDevices.size());
            statistics.put("offlineDevices", devices.size() - onlineDevices.size());
            
            // 按设备类型统计
            Map<String, Long> deviceTypeStats = devices.stream()
                    .collect(Collectors.groupingBy(
                            device -> device.getDeviceType() != null ? device.getDeviceType() : "未知",
                            Collectors.counting()
                    ));
            statistics.put("deviceTypeStats", deviceTypeStats);
            
            // 可信设备数量
            long trustedCount = devices.stream()
                    .mapToLong(device -> isDeviceTrusted(userId, device.getDeviceId()) ? 1 : 0)
                    .sum();
            statistics.put("trustedDevices", trustedCount);
            
        } catch (Exception e) {
            log.error("获取设备统计信息失败: {}", e.getMessage(), e);
        }
        
        return statistics;
    }

    @Override
    public List<UserDeviceDTO> detectAbnormalDevices(Long userId) {
        List<UserDeviceDTO> abnormalDevices = new ArrayList<>();
        
        try {
            List<UserDeviceDTO> devices = getUserDevices(userId);
            
            for (UserDeviceDTO device : devices) {
                // 检查登录频率是否异常
                if (isDeviceLoginFrequencyAbnormal(userId, device.getDeviceId(), 60, 10)) {
                    device.setStatus(2); // 异常状态
                    abnormalDevices.add(device);
                }
                
                // 检查是否为新设备且未可信
                if (!isDeviceTrusted(userId, device.getDeviceId()) && 
                    device.getLoginTime() != null &&
                    (System.currentTimeMillis() - device.getLoginTime().getTime()) < 24 * 60 * 60 * 1000) {
                    // 24小时内的新设备
                    abnormalDevices.add(device);
                }
            }
            
        } catch (Exception e) {
            log.error("检测异常设备失败: {}", e.getMessage(), e);
        }
        
        return abnormalDevices;
    }

    @Override
    public String generateDeviceFingerprint(HttpServletRequest request) {
        try {
            StringBuilder fingerprint = new StringBuilder();
            
            // 用户代理
            String userAgent = request.getHeader("User-Agent");
            if (userAgent != null) {
                fingerprint.append(userAgent);
            }
            
            // Accept语言
            String acceptLanguage = request.getHeader("Accept-Language");
            if (acceptLanguage != null) {
                fingerprint.append(acceptLanguage);
            }
            
            // Accept编码
            String acceptEncoding = request.getHeader("Accept-Encoding");
            if (acceptEncoding != null) {
                fingerprint.append(acceptEncoding);
            }
            
            // 生成MD5哈希
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hash = md.digest(fingerprint.toString().getBytes());
            
            StringBuilder hexString = new StringBuilder();
            for (byte b : hash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            
            return hexString.toString();
            
        } catch (Exception e) {
            log.error("生成设备指纹失败: {}", e.getMessage(), e);
            return UUID.randomUUID().toString().replace("-", "");
        }
    }

    @Override
    public Map<String, String> parseUserAgent(String userAgent) {
        Map<String, String> result = new HashMap<>();
        
        if (userAgent == null || userAgent.trim().isEmpty()) {
            result.put("browser", "Unknown");
            result.put("os", "Unknown");
            return result;
        }
        
        // 简单的浏览器检测
        String browser = "Unknown";
        if (userAgent.contains("Chrome")) {
            browser = "Chrome";
        } else if (userAgent.contains("Firefox")) {
            browser = "Firefox";
        } else if (userAgent.contains("Safari")) {
            browser = "Safari";
        } else if (userAgent.contains("Edge")) {
            browser = "Edge";
        } else if (userAgent.contains("Opera")) {
            browser = "Opera";
        }
        
        // 简单的操作系统检测
        String os = "Unknown";
        if (userAgent.contains("Windows")) {
            os = "Windows";
        } else if (userAgent.contains("Mac")) {
            os = "macOS";
        } else if (userAgent.contains("Linux")) {
            os = "Linux";
        } else if (userAgent.contains("Android")) {
            os = "Android";
        } else if (userAgent.contains("iOS")) {
            os = "iOS";
        }
        
        result.put("browser", browser);
        result.put("os", os);
        
        return result;
    }

    @Override
    public String getDeviceTypeName(Integer clientType) {
        if (clientType == null) {
            return "未知设备";
        }
        switch (clientType) {
            case 0: return "Web端";
            case 1: return "iOS端";
            case 2: return "安卓端";
            case 3: return "Windows端";
            case 4: return "macOS端";
            case 5: return "鸿蒙端";
            default: return "未知设备";
        }
    }

    @Override
    public boolean isDeviceLoginFrequencyAbnormal(Long userId, String deviceId, 
                                                 int timeWindowMinutes, int maxAttempts) {
        try {
            String key = DEVICE_LOGIN_ATTEMPTS_KEY + userId + ":" + deviceId;
            Object attempts = cloudRedisTemplateService.get(new CloudRedisVO(key));
            
            if (attempts != null) {
                int count = Integer.parseInt(attempts.toString());
                return count > maxAttempts;
            }
        } catch (Exception e) {
            log.error("检查设备登录频率失败: {}", e.getMessage(), e);
        }
        return false;
    }

    @Override
    public void recordDeviceLoginAttempt(Long userId, String deviceId, boolean success, String ip) {
        try {
            String key = DEVICE_LOGIN_ATTEMPTS_KEY + userId + ":" + deviceId;
            Object attempts = cloudRedisTemplateService.get(new CloudRedisVO(key));
            
            int count = attempts != null ? Integer.parseInt(attempts.toString()) : 0;
            count++;
            
            // 记录1小时
            cloudRedisTemplateService.set(new CloudRedisVO(key, String.valueOf(count), 3600L));
            
        } catch (Exception e) {
            log.error("记录设备登录尝试失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 转换设备对象
     */
    private UserDeviceDTO convertToUserDeviceDTO(ConcurrentLoginManager.LoginDevice device) {
        UserDeviceDTO dto = new UserDeviceDTO();
        dto.setDeviceId(device.getDeviceId());
        dto.setDeviceName(device.getDeviceName());
        dto.setDeviceType(device.getDeviceType());
        dto.setLoginIp(device.getLoginIp());
        dto.setLoginTime(device.getLoginTime());
        dto.setLastActiveTime(device.getLastActiveTime());
        dto.setToken(device.getToken());
        dto.setIsOnline(dto.isActive(30)); // 30分钟内活跃
        dto.calculateSessionDuration();
        
        return dto;
    }
}
